/**                   GNU GENERAL PUBLIC LICENSE
 *                       Version 3, 29 June 2007
 *
 * Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
 * Everyone is permitted to copy and distribute verbatim copies
 * of this license document, but changing it is not allowed.
 * See License.txt file that comes with this distribution
 *
 * Description: Bound any key to a function.
 *
 * Author: Vitaly German <vitaly.german@gmail.com>, (C) 2007-2008
 * 
 **/

#pragma once
#include <iostream>
#include <map>

template <class FunT, class KeyT, class MarkTraits >
class Key2Fun {
public:
    typedef FunT Fun;
    typedef Key2Fun<FunT, KeyT, MarkTraits> self;

private:
    typedef typename std::map<KeyT, FunT, std::less<KeyT> > ID2Fun;
    ID2Fun id2fun;
    Fun defaultFun; // called when nothing is in map

public:

    template <class Node>
    typename Fun::result_type  operator()(Node node) const {
        Fun f = FindFun(node);
        return f(node);
    }

    template <class Node1, class Node2>
    typename Fun::result_type  operator()(Node1 node1, Node2 node2) const {
        Fun f = FindFun(node1);
        return f(node1, node2);
    }

    void RegisterFun( const KeyT &mark, Fun f, bool IsDefaultFun = false) {
        if (!IsDefaultFun) {
            id2fun[mark] = f;
        } else {
            defaultFun = f;
        }
    }
    bool UnRegisterFun( const KeyT &mark) {
        typename ID2Fun::const_iterator it;
        if ((it = id2fun.find(mark)) != id2fun.end()) {
            id2fun.erase(it);
            return true;
        }
        return false;
    }
    bool UnRegisterFun() {
        defaultFun = Fun();
        return true;
    }
    void stat() {
        rfm_solver::debug("\nKey2Fun ",id2fun.size()," functions registread.\n");
        int count = 0;
        for(typename ID2Fun::iterator it = id2fun.begin(); it!=id2fun.end(); ++it) {
            ++count;
            rfm_solver::debug(it->first,"\t");
            if (it->second) {
                rfm_solver::debug("\nValid fun obj");
            } else {
                rfm_solver::debug("\nINVALID fun obj");
            }
        }
        rfm_solver::debug("\nTotal:");
        rfm_solver::debug("\n");
    }
private:

    template <class Node>
    Fun FindFun(const Node& node) const {
        rfm_solver::debug("\nFindFun::Node: ");
#ifdef DEBUG
        prn(node);
#endif
        KeyT mrk = MarkTraits::GetMark(node);
        typename ID2Fun::const_iterator it = id2fun.find(mrk);
        if (it!= id2fun.end()) {
            rfm_solver::debug("\nFound: ",it->first,"!");
            return it->second;
        }
        rfm_solver::debug("\nUnknown.");
        return defaultFun;
    }
};
